package hash;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


public class Hasher {
	
	/**
	 * Create Checksum for given file.
	 * <p>
	 * @param file - File to digest
	 * @return Wrapper of Checksum results
	 */
	ResultWrapper createChecksum(File file)
	{		
		ResultWrapper results = null;
		try
		{
			byte[] md5 = calculateHash(file, MessageDigest.getInstance("MD5"));
			byte[] sha1 = calculateHash(file, MessageDigest.getInstance("SHA1"));
			results = new ResultWrapper(getHex(md5), getHex(sha1));
		}
		catch (NoSuchAlgorithmException e) { e.printStackTrace(); }
		return results;
	}
	
	
	/**
	 * Calculate checksum based on MessageDigest type.
	 * <p>
	 * @param file - File to digest
	 * @param checksum - Type of MessageDigest. e.g. MD5, SHA1, etc...
	 * @return - Byte array of checksum
	 */
	byte[] calculateHash(File file, MessageDigest checksum)
	{		
		try
		{			
			InputStream fis = new FileInputStream(file);
			byte[] buffer = new byte[1024];			
			int numRead;			
			do {
				numRead = fis.read(buffer);
				if (numRead > 0)
					checksum.update(buffer, 0, numRead);				
			} while (numRead != -1);
			fis.close();
		}
		catch (FileNotFoundException e) { e.printStackTrace(); }
		catch (IOException e) { e.printStackTrace(); }		
		return checksum.digest();
	}
	
	
	/**
	 * Return Hex String for byte array from digested file
	 * <p>
	 * @param buffer - Byte array of checksum
	 * @return - HexString representing byte array.
	 */
	String getHex(byte[] buffer)
	{
		StringBuffer result = new StringBuffer();
		for (int i = 0; i < buffer.length; i++)
			result.append(Integer.toHexString((buffer[i] & 0xFF) | 0x100).substring(1,3));		
		return result.toString();
	}
	 
}


/**
 * Wrapper Class used to hold results of digested file.
 * Should eventually expand to allow for more MessageDigest types.
 */
class ResultWrapper {
	String md5;
	String sha1;
	
	ResultWrapper() { }
	ResultWrapper(String md5, String sha1)
	{
		this.md5 = md5;
		this.sha1 = sha1;
	}
	
	/**
	 * Set SHA1 Value
	 * <p>
	 * @param sha1 - SHA1 Value
	 */
	void setSHA1(String sha1) { this.sha1 = sha1; }
	
	/**
	 * Retrieve SHA1 Value.
	 * <p>
	 * @return - SHA1 Value
	 */
	String getSHA1() { return this.sha1; }
	
	/**
	 * Set MD5 Value
	 * <p>
	 * @param md5 - MD5 Value
	 */
	void setMD5(String md5) { this.md5 = md5; }
	
	/**
	 * Retrieve MD5 Value.
	 * <p>
	 * @return - MD5 value
	 */
	String getMD5() { return this.md5; }
}

